<template>
  <div class="app-container">
    <el-row :gutter="20">
      <el-col :span="4">
        <el-input
          v-model="deptName"
          placeholder="请输入部门名称"
          prefix-icon="Search"
        />
        <el-tree
          ref="deptTreeRef"
          style="max-width: 600px; margin-top: 16px"
          highlight-current
          :data="deptOptions"
          :filter-node-method="filterNode"
          node-key="dept_id"
          :props="{
            value: 'dept_id',
            label: 'dept_name',
            children: 'children',
          }"
          @node-click="handleNodeClick"
        />
      </el-col>
      <el-col :span="20">
        <el-form ref="queryFormRef" :model="page.queryForm" inline>
          <el-form-item label="用户名称" prop="username">
            <el-input
              v-model="page.queryForm.username"
              placeholder="请输入用户名称"
              clearable
              @keyup.enter="getUserList"
            />
          </el-form-item>

          <el-form-item label="手机号码" prop="mobile">
            <el-input
              v-model="page.queryForm.mobile"
              placeholder="请输入手机号码"
              clearable
              @keyup.enter="getUserList"
            />
          </el-form-item>

          <el-form-item label="状态" prop="status">
            <el-select v-model="page.queryForm.status" style="width: 140px">
              <el-option label="正常" value="0" />
              <el-option label="停用" value="1" />
            </el-select>
          </el-form-item>

          <el-form-item label="创建时间" prop="create_time">
            <el-date-picker
              v-model="daterange"
              type="daterange"
              format="YYYY-MM-DD"
              range-separator="至"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              @change="handleDateChange"
            />
          </el-form-item>

          <el-form-item>
            <el-button type="primary" icon="Search" @click="getUserList"
              >搜索</el-button
            >
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>

        <vxe-toolbar
          ref="toolbarRef"
          custom
          print
          :refresh="{ query: getUserList }"
        >
          <template #buttons>
            <el-button type="primary" icon="Plus" plain @click="handleAdd()"
              >新增</el-button
            >
            <el-button type="success" icon="Edit" plain @click="handleUpdate()"
              >修改</el-button
            >
            <el-popconfirm
              title="您确定要删除选中的数据吗?"
              confirm-button-text="确认"
              cancel-button-text="取消"
              @confirm="handleDelete()"
            >
              <template #reference>
                <el-button type="danger" icon="Delete" plain>删除</el-button>
              </template>
            </el-popconfirm>
            <el-button
              type="warning"
              icon="Download"
              plain
              @click="handleExport()"
              >导出</el-button
            >
          </template>
        </vxe-toolbar>

        <vxe-table
          ref="userTableRef"
          border="inner"
          align="center"
          :column-config="{ resizable: true }"
          :row-config="{ isHover: true }"
          :print-config="{}"
          :loading="loading"
          :data="tableData"
          @checkbox-all="selectAllChangeEvent"
          @checkbox-change="selectChangeEvent"
        >
          <vxe-column type="checkbox" width="60"></vxe-column>
          <vxe-column field="id" title="用户ID" width="100"></vxe-column>
          <vxe-column field="username" title="用户名称"></vxe-column>
          <vxe-column field="nickname" title="用户昵称"></vxe-column>
          <vxe-column field="dept_name" title="部门"></vxe-column>
          <vxe-column field="mobile" title="手机号码"></vxe-column>
          <vxe-column title="状态">
            <template #default="{ row }">
              <el-switch
                v-model="row.status"
                active-value="0"
                inactive-value="1"
                @change="handleStatusChange(row)"
              ></el-switch>
            </template>
          </vxe-column>
          <vxe-column field="create_time" title="创建时间"></vxe-column>
          <vxe-column title="操作" min-width="180">
            <template #default="{ row }">
              <el-button
                v-if="row.id != 1"
                link
                type="primary"
                icon="Edit"
                @click="handleUpdate(row)"
                >修改</el-button
              >
              <el-popconfirm
                v-if="row.id != 1"
                title="您确定要删除此数据吗?"
                confirm-button-text="确认"
                cancel-button-text="取消"
                @confirm="handleDelete(row)"
              >
                <template #reference>
                  <el-button link type="primary" icon="Delete">删除</el-button>
                </template>
              </el-popconfirm>

              <el-button
                v-if="row.id != 1"
                link
                type="primary"
                icon="key"
                @click="resetPassword(row)"
                >重置密码</el-button
              >
            </template>
          </vxe-column>
        </vxe-table>

        <el-row justify="end" style="padding: 16px">
          <el-pagination
            v-show="page.total > 0"
            v-model:current-page="page.queryForm.pageNum"
            v-model:page-size="page.queryForm.pageSize"
            :page-sizes="[10, 20, 30, 40]"
            layout="total, sizes, prev, pager, next, jumper"
            :total="page.total"
            @size-change="getUserList"
            @current-change="getUserList"
          />
        </el-row>

        <!-- 新增、修改对话框的显示与隐藏 -->
        <el-dialog
          v-model="open"
          :title="title"
          width="700px"
          append-to-body
          destroy-on-close
          @closed="reset"
        >
          <el-form
            ref="formRef"
            :model="page.form"
            :rules="page.rules"
            label-width="90px"
          >
            <el-row :gutter="10">
              <el-col :span="12" v-if="!page.form.id">
                <el-form-item prop="username">
                  <template #label>
                    <span>
                      <el-tooltip content="用做登录账号" placement="top">
                        <el-icon><question-filled /></el-icon>
                      </el-tooltip>
                      用户名
                    </span>
                  </template>
                  <el-input
                    v-model="page.form.username"
                    placeholder="请输入用户名"
                    clearable
                  />
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="部门" prop="dept_id">
                  <el-tree-select
                    v-model="page.form.dept_id"
                    :props="{
                      value: 'dept_id',
                      label: 'dept_name',
                      children: 'children',
                    }"
                    value-key="dept_id"
                    :data="deptOptions"
                    check-strictly
                    placeholder="请选择所属部门"
                  />
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="昵称" prop="nickname">
                  <el-input
                    v-model="page.form.nickname"
                    placeholder="请输入昵称"
                    clearable
                  />
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="手机号" prop="mobile">
                  <el-input
                    v-model="page.form.mobile"
                    placeholder="请输入手机号"
                    clearable
                  />
                </el-form-item>
              </el-col>

              <el-col :span="12" v-if="!page.form.id">
                <el-form-item label="密码" prop="password">
                  <el-input
                    v-model="page.form.password"
                    placeholder="请输入用户密码"
                    clearable
                  />
                </el-form-item>
              </el-col>

              <el-col :span="12">
                <el-form-item label="邮箱" prop="email">
                  <el-input
                    v-model="page.form.email"
                    placeholder="请输入邮箱"
                    clearable
                  />
                </el-form-item>
              </el-col>

              <el-col :span="12">
                <el-form-item label="性别" prop="gender">
                  <el-select v-model="page.form.gender" placeholder="请选择">
                    <el-option
                      v-for="item in sexOptions"
                      :key="item.value"
                      :label="item.label"
                      :value="item.value"
                    ></el-option>
                  </el-select>
                </el-form-item>
              </el-col>

              <el-col :span="12">
                <el-form-item label="状态" prop="status">
                  <el-radio-group v-model="page.form.status">
                    <el-radio :label="0">正常</el-radio>
                    <el-radio :label="1">停用</el-radio>
                  </el-radio-group>
                </el-form-item>
              </el-col>

              <el-col :span="12">
                <el-form-item label="岗位" prop="postIds">
                  <el-select
                    v-model="page.form.postIds"
                    multiple
                    placeholder="请选择"
                  >
                    <el-option
                      v-for="item in postOptions"
                      :key="item.value"
                      :label="item.label"
                      :value="item.value"
                    ></el-option>
                  </el-select>
                </el-form-item>
              </el-col>

              <el-col :span="12">
                <el-form-item label="角色" prop="roleIds">
                  <el-select
                    v-model="page.roleIds"
                    multiple
                    placeholder="请选择"
                  >
                    <el-option
                      v-for="item in roleOptions"
                      :key="item.value"
                      :label="item.label"
                      :value="item.value"
                    ></el-option>
                  </el-select>
                </el-form-item>
              </el-col>
            </el-row>
            <el-form-item label="备注" prop="remark">
              <el-input
                v-model="page.form.remark"
                type="textarea"
                placeholder="请输入内容"
              ></el-input>
            </el-form-item>
          </el-form>
          <template #footer>
            <el-button @click="cancel">取消</el-button>
            <el-button type="primary" @click="submit">确认</el-button>
          </template>
        </el-dialog>
      </el-col>
    </el-row>
  </div>
</template>

<script setup>
import { ref, reactive, onMounted, nextTick, watch } from "vue";
import {
  userList,
  userAdd,
  userEdit,
  userDel,
  userInfo,
  userExport,
  resetPwd
} from "@/api/system/user.ts";
import { deptList } from "@/api/system/dept.ts";
import { roleList } from "@/api/system/role.ts";
import { downloadFile } from "@/utils/download.ts";

const deptTreeRef = ref(null);
const queryFormRef = ref(null);
const daterange = ref([]);
const toolbarRef = ref(null);
const userTableRef = ref(null);
const formRef = ref();

const page = reactive({
  // 查询表单
  queryForm: {
    dept_id: null,
    username: null,
    mobile: null,
    status: null,
    begin_time: null,
    end_time: null,
    pageNum: 1,
    pageSize: 10,
  },
  roleIds: [],
  total: 0,
  // 新增、修改表单
  form: {},
  // 新增、修改表单验证规则
  rules: {
    username: [
      { required: true, message: "用户名称不能为空", trigger: "blur" },
    ],
    nickname: [
      { required: true, message: "用户昵称不能为空", trigger: "blur" },
    ],
    password: [
      { required: true, message: "用户密码不能为空", trigger: "blur" },
      {
        min: 6,
        max: 20,
        message: "用户密码长度必须介于 6 和 20 之间",
        trigger: "blur",
      },
      {
        pattern: /^[^<>"'|\\]+$/,
        message: "不能包含非法字符：< > \" ' \\\ |",
        trigger: "blur",
      },
    ],
  },
});

// 表格数据
const tableData = ref([]);
// 选中的表格ID
const checkedIds = ref([]);
// 加载状态
const loading = ref(false);
// 新增、修改对话框的显示与隐藏
const open = ref(false);
// 对话框标题
const title = ref("");
// 部门名称
const deptName = ref();
// 部门树选项
const deptOptions = ref([]);
// 岗位选项
const postOptions = ref([]);
// 角色选项
const roleOptions = ref([]);
// 性别选项
const sexOptions = [
  {
    label: "男",
    value: 1,
  },
  {
    label: "女",
    value: 2,
  },
  {
    label: "未知",
    value: 3,
  },
];

nextTick(() => {
  // 将表格和工具栏进行关联
  const $table = userTableRef.value;
  const $toolbar = toolbarRef.value;
  if ($table && $toolbar) {
    $table.connect($toolbar);
  }
});

watch(deptName, (value) => {
  deptTreeRef.value.filter(value);
});

onMounted(() => {
  getUserList();
  resetForm();
  getDeptTree();
  getRoleList();
});

/**
 * 创建日期范围改变
 * @param {*} e
 */
function handleDateChange(e) {
  if (e) {
    page.queryForm.begin_time = e[0];
    page.queryForm.end_time = e[1];
  } else {
    page.queryForm.begin_time = null;
    page.queryForm.end_time = null;
  }
}

/**
 * 重置查询
 */
function resetQuery() {
  queryFormRef.value.resetFields();
  daterange.value = [];
  page.queryForm.begin_time = null;
  page.queryForm.end_time = null;
  page.queryForm.dept_id = null;
  deptTreeRef.value.setCurrentKey(null);
  getUserList();
}

/**
 * 表格全选事件
 * @param {*} e
 */
function selectAllChangeEvent(e) {
  checkedIds.value = e.records.map((item) => item.id);
}

/**
 * 表格选中事件
 * @param {*} e
 */
function selectChangeEvent(e) {
  checkedIds.value = e.records.map((item) => item.id);
}

/**
 * 新增用户
 */
function handleAdd() {
  open.value = true;
  title.value = "新增用户";
}

/**
 * 修改用户
 * @param {*} row
 */
function handleUpdate(row) {
  let ids = row ? [row.id] : checkedIds.value;
  console.log("🚀 ~ handleUpdate ~ ids:", ids)
  if (ids.length == 0) {
    return ElMessage.warning("请选择要修改的用户");
  } else if (ids.length > 1) {
    return ElMessage.warning("只能选择一个用户");
  }
  userInfo(ids[0]).then((res) => {
    open.value = true;
    title.value = "修改角色";
    // 文档说的是重置为初始值，当我们打开对话框时，我们已经赋值完毕了，所以使用resetFields会重置到赋完值的状态
    // 这里，我们借助nextTick去修改数据渲染页面：(不要忘记引用nextTick)
    nextTick(() => {
      page.form = {
        ...res.data,
        status: Number(res.data.status),
        gender: Number(res.data.gender),
      };
      delete page.form.roles;
      page.roleIds = res.data.roles
        ? res.data.roles.split(",").map((k) => Number(k))
        : [];
    });
  });
}

/**
 * 删除用户
 * @param {*} row
 */
function handleDelete(row) {
  let ids = row ? [row.id] : checkedIds.value;
  if (ids.length == 0) {
    return ElMessage.warning("请选择要删除的用户");
  }
  userDel({ userIds: ids }).then((res) => {
    getUserList();
  });
}

/**
 * 获取用户列表
 */
function getUserList() {
  loading.value = true;
  userList(page.queryForm)
    .then((res) => {
      tableData.value = res.data.list;
      page.total = res.data.total;
    })
    .finally(() => {
      loading.value = false;
    });
}

/**
 * 获取部门树
 */
function getDeptTree() {
  deptList().then((res) => {
    deptOptions.value = listToDeptTree(res.data, "0");
  });
}

/**
 * 列表转部门树
 * @param {Array} list 列表
 * @param {String} parentId 父级id
 */
function listToDeptTree(list, parentId) {
  return list
    .filter((item) => item.parent_id === parentId)
    .map((item) => ({
      ...item,
      dept_id: Number(item.dept_id),
      children: listToDeptTree(list, item.dept_id),
    }));
}

/**
 * 处理树节点过滤事件
 * @param {String} value 搜索值
 * @param {Object} data 树节点数据
 */
function filterNode(value, data) {
  if (!value) return true;
  return data.dept_name.indexOf(value) !== -1;
}

/**
 * 处理树节点点击事件
 * @param {Object} e 树节点数据
 */
function handleNodeClick(e) {
  page.queryForm.dept_id = e.dept_id;
  getUserList();
}

/**
 * 获取角色列表
 */
function getRoleList() {
  roleList().then((res) => {
    roleOptions.value = res.data.list.map((k) => {
      return {
        label: k.role_name,
        value: k.role_id,
      };
    });
  });
}

/**
 * 处理用户状态改变事件
 * @param {Object} row 行数据
 */
function handleStatusChange(row) {
  userEdit(row.id, { status: row.status }).then(() => {
    ElMessage.success("操作成功");
    getUserList();
  });
}

/**
 * 提交新增、修改
 */
function submit() {
  formRef.value.validate((valid) => {
    if (valid) {
      if (page.form.id) {
        userEdit(page.form.id, { user: page.form, roles: page.roleIds }).then(
          () => {
            open.value = false;
            ElMessage.success("操作成功");
            getUserList();
          }
        );
      } else {
        userAdd({ user: page.form, roleIds: page.roleIds }).then(() => {
          open.value = false;
          ElMessage.success("操作成功");
          getUserList();
        });
      }
    }
  });
}

/**
 * 取消
 */
function cancel() {
  open.value = false;
}

/**
 * 重置
 */
function reset() {
  resetForm();
  page.roleIds = [];
}

/**
 * 重置表单
 */
function resetForm() {
  page.form = {
    id: null,
    username: null,
    nickname: null,
    email: null,
    phone: null,
    gender: 1,
    status: 0,
    dept_id: null,
    remark: null,
    password: null,
  };
}

/**
 * 重置密码
 * @param {*} row
 */
function resetPassword(row) {
  ElMessageBox.prompt('请输入"' + row.nickname + '"的新密码', "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    closeOnClickModal: false,
    inputPattern: /^.{6,20}$/,
    inputErrorMessage: "用户密码长度必须介于 6 和 20 之间",
    inputValidator: (value) => {
      if (/<|>|"|'|\||\\/.test(value)) {
        return "不能包含非法字符：< > \" ' \\\ |";
      }
    },
  })
    .then(({ value }) => {
      resetPwd({ id:row.id,password: value })
        .then(() => {
          ElMessage({
            type: "success",
            message: `修改成功！新密码是:${value}`,
          });
        })
        .catch((err) => {
          ElMessage({
            type: "error",
            message: err.msg || "修改失败",
          });
        });
    })
    .catch();
}

/**
 * 导出
 */
function handleExport() {
  userExport().then(res => {
    downloadFile(res)
  })
}
</script>

<style lang="scss" scoped></style>
